package cn.sdack.go.users.service;

import cn.sdack.go.common.entities.users.DictEntity;
import cn.sdack.go.common.entities.users.DictItemEntity;
import cn.sdack.go.common.querys.users.AuthorityQuery;
import cn.sdack.go.common.querys.users.DictQuery;
import cn.sdack.go.users.dao.DictDao;
import cn.sdack.go.users.dao.DictItemDao;
import com.alibaba.fastjson2.JSONObject;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.endsWith;

/**
 * @author sdack
 * @date 2024/2/17
 */
@Service
public class DictServiceImpl implements DictService {

    @Autowired
    private DictDao dictDao;

    @Autowired
    private DictItemDao dictItemDao;


    @Override
    public Page<DictEntity> queryAll(DictQuery param,int page, int pageSize) {
        ExampleMatcher matcher = ExampleMatcher.matchingAny()
                .withIgnoreNullValues()
                .withMatcher(AuthorityQuery.CODE, endsWith())
                .withMatcher(AuthorityQuery.NAME, endsWith())
                ;

        DictEntity query = JSONObject.parseObject(JSONObject.toJSONString(param), DictEntity.class);
        Example<DictEntity> example = Example.of(query, matcher);
        return dictDao.findAll(example, PageRequest.of(page <= 0 ? 0 : page - 1, pageSize, Sort.by(Sort.Order.desc("id"))));
    }

    @Override
    public DictEntity getById(Long id) throws Exception {
        Optional<DictEntity> optional = dictDao.findById(id);
        if (optional.isEmpty()) {
            throw new IllegalAccessException("non-existent");
        }
        return optional.get();
    }

    @Override
    public DictEntity getByCode(String code) throws Exception {
        DictEntity entity = dictDao.findByCodeAndDelIsNull(code);
        if (entity == null) {
            throw new IllegalAccessException("non-existent");
        }
        List<DictItemEntity> list = dictItemDao.findAllByCodeAndDelIsNull(entity.getCode());
        entity.setItemList(list);
        return dictDao.save(entity);
    }

    @Override
    public DictItemEntity getByCode(Long id) throws Exception {
        Optional<DictItemEntity> optional = dictItemDao.findById(id);
        if (optional.isEmpty()) {
            throw new IllegalAccessException("non-existent");
        }
        if (optional.get().getDel() != null) {
            throw new IllegalAccessException("non-existent");
        }
        return optional.get();
    }

    @Transactional
    @Override
    public DictEntity add(DictEntity param) throws Exception {
        param.setId(null);
        List<DictEntity> list = dictDao.findAllByCodeAndDelIsNull(param.getCode());
        if (!list.isEmpty()) {
            throw new IllegalAccessException("code 存在重复");
        }
        DictEntity save = dictDao.save(param);
        if (param.getItemList() != null) {
            for (DictItemEntity itemEntity : param.getItemList()) {
                itemEntity.setId(null);
                itemEntity.setPid(save.getId());
                itemEntity.setCode(save.getCode());
            }
            long count = param.getItemList().stream().map(DictItemEntity::getV).distinct().count();
            if (count != param.getItemList().size()) {
                throw new  IllegalAccessException("字典项值存在重复");
            }
            dictItemDao.saveAll(param.getItemList());
        } else {
            DictItemEntity build = new DictItemEntity();
            build.setPid(save.getId());
            build.setV("0");
            build.setName("Default");
            build.setCode(save.getCode());
            dictItemDao.save(build);
        }
        return save;
    }

    @Transactional
    @Override
    public DictItemEntity addItem(DictItemEntity param) throws Exception {
        DictEntity entity = getByCode(param.getCode());
        param.setPid(entity.getId());

        List<DictItemEntity> all = dictItemDao.findAllByPidAndVAndDelIsNull(entity.getId(), param.getV());
        if (!all.isEmpty()) {
            throw new IllegalAccessException("值已经存在");
        }
        return dictItemDao.save(param);
    }

    @Transactional
    @Override
    public DictEntity edit(DictEntity param) throws Exception {
        DictEntity entity = getById(param.getId());

        if (StringUtils.hasLength(param.getCode())) {
            if (!entity.getCode().equals(param.getCode())) {
                List<DictEntity> list = dictDao.findAllByCodeAndDelIsNull(param.getCode());
                if (!list.isEmpty()) {
                    throw new IllegalAccessException("code 存在重复");
                }
                List<DictItemEntity> all = dictItemDao.findAllByCodeAndDelIsNull(entity.getCode());
                entity.setCode(param.getCode());
                all.forEach(it -> it.setCode(param.getCode()));
                dictItemDao.saveAll(all);
            }
        }

        if (StringUtils.hasLength(param.getName())) {
            entity.setName(param.getName());
        }
        return dictDao.save(entity);
    }

    @Transactional
    @Override
    public DictItemEntity editItem(DictItemEntity param) throws Exception {
        DictItemEntity itemEntity = getByCode(param.getId());

        if (StringUtils.hasLength(param.getV())) {
            if (!itemEntity.getV().equals(param.getV())) {
                List<DictItemEntity> all = dictItemDao.findAllByPidAndVAndDelIsNull(itemEntity.getPid(), param.getV());
                if (!all.isEmpty()) {
                    if (all.size() == 1) {
                        DictItemEntity entity = all.get(0);
                        if (entity.getId() != itemEntity.getId().longValue()) {
                            throw new IllegalAccessException("值存在重复");
                        }
                    } else {
                        throw new IllegalAccessException("值存在重复");
                    }
                }
            }
        }

        if (StringUtils.hasLength(param.getName())) {
            itemEntity.setName(param.getName());
        }
        if (StringUtils.hasLength(param.getRemark())) {
            itemEntity.setRemark(param.getRemark());
        }
        return dictItemDao.save(itemEntity);
    }

    @Transactional
    @Override
    public DictEntity status(String code, Integer status) throws Exception {
        DictEntity entity = getByCode(code);
        entity.setStatus(status != 0);
        return dictDao.save(entity);
    }

    @Transactional
    @Override
    public DictItemEntity statusItem(Long id, Integer status) throws Exception {
        DictItemEntity entity = getByCode(id);
        entity.setStatus(status != 0);
        return dictItemDao.save(entity);
    }

    @Transactional
    @Override
    public void del(String code) throws Exception {
        LocalDateTime now = LocalDateTime.now();
        DictEntity entity = getByCode(code);
        if (entity.getItemList() != null) {
            entity.getItemList().forEach(it -> it.setDel(now));
            dictItemDao.saveAll(entity.getItemList());
        }
        entity.setDel(now);
        dictDao.save(entity);
    }

    @Transactional
    @Override
    public void delItem(Long id) throws Exception {
        DictItemEntity entity = getByCode(id);
        entity.setDel(LocalDateTime.now());
        dictItemDao.save(entity);
    }

}
